package com.pvdnc.riru.system_server;

import android.annotation.SuppressLint;
import android.os.IBinder;
import android.util.Log;

import com.pvdnc.riru.UserUtils;
import com.pvdnc.riru.common.ServiceObserver;
import com.pvdnc.riru.system_server.filter.PackageFilterManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

import andhook.lib.xposed.XC_MethodHook;
import andhook.lib.xposed.XposedBridge;

@SuppressLint({"SoonBlockedPrivateApi","PrivateApi"})
public class HookBatteryStatsService extends ServiceObserver {
    public static final HookBatteryStatsService INSTANCE=new HookBatteryStatsService();

    private static final String TAG=HookBatteryStatsService.class.getSimpleName();

    @Override
    public void onServiceAdd(String name, IBinder service) {
        Class<?> serviceClass=service.getClass();
        Log.d(TAG,"service class:"+serviceClass);
        ClassLoader cl=serviceClass.getClassLoader();
        try{
            Objects.requireNonNull(cl);
            hookBatteryStatsService(cl);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static final boolean BLOCK_ALL_RECORD=false;

    private class BatteryStatsImplHookHandler extends XC_MethodHook{
        private final Class<?> mBSIUidClass;

        public BatteryStatsImplHookHandler(Class<?> bsiUidClass){
            mBSIUidClass=bsiUidClass;
        }

        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            try {
                String methodName=param.method.getName();
                Log.d(TAG, "invoke before " + methodName);
                //获取uid
                Field uidField = mBSIUidClass.getDeclaredField("mUid");
                uidField.setAccessible(true);
                int mUid = uidField.getInt(param.thisObject);
                if(!shouldBlockAndReset(mUid))
                    return;
                Log.d(TAG, "attempt to intercept "+methodName+" " +
                        "for uid:" + mUid);
                //清除记录
                Method resetMethod = mBSIUidClass.getDeclaredMethod("reset");//boolean reset()
                resetMethod.setAccessible(true);
                resetMethod.invoke(param.thisObject);
                //跳过调用
                param.setResult(null);
            }catch (Exception e){
                e.printStackTrace();
            }
        }


        private boolean shouldBlockAndReset(int uid){
            if(BLOCK_ALL_RECORD)
                return true;
            if(!UserUtils.isUserUid(uid))
                return true;
            //按包名过滤
            String pkgName=PMSUtils.get().getPackageNameForUid(uid);
            if(PackageFilterManager.INSTANCE.callFilter(pkgName)){
                return true;
            }
            return false;
        }
    }

    private void hookBatteryStatsService(ClassLoader cl) throws Exception {
        final Class<?> bsiUidClass = cl.loadClass("com.android.internal.os.BatteryStatsImpl$Uid");
        //void noteNetworkActivityLocked(int type, long deltaBytes, long deltaPackets)
        Method noteNAMethod = bsiUidClass.getDeclaredMethod("noteNetworkActivityLocked", int.class, long.class, long.class);
        XposedBridge.hookMethod(noteNAMethod,new BatteryStatsImplHookHandler(bsiUidClass));

        // public void noteCameraTurnedOnLocked(long elapsedRealtimeMs)
        Method noteCameraOnMethod = bsiUidClass.getDeclaredMethod("noteCameraTurnedOnLocked", long.class);
        XposedBridge.hookMethod(noteCameraOnMethod, new BatteryStatsImplHookHandler(bsiUidClass));

        //public void noteCameraTurnedOffLocked(long elapsedRealtimeMs)
        Method noteCameraOffMethod = bsiUidClass.getDeclaredMethod("noteCameraTurnedOffLocked", long.class);
        XposedBridge.hookMethod(noteCameraOffMethod, new BatteryStatsImplHookHandler(bsiUidClass));
        Log.d(TAG, "hook BatteryStatsService finished");
    }
}
